package com.usian.wemedia.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.usian.common.constants.message.NewsAutoScanConstants;
import com.usian.common.constants.message.WmNewsUpDownConstants;
import com.usian.common.dtos.PageResult;
import com.usian.common.enums.AppHttpCodeEnum;
import com.usian.common.exception.LeadException;
import com.usian.common.threadlocal.UserThreadLocalUtils;
import com.usian.common.util.BeanHelper;
import com.usian.common.util.JsonUtils;
import com.usian.model.admin.dtos.NewsAuthDto;
import com.usian.model.media.dtos.WmNewsDto;
import com.usian.model.media.dtos.WmNewsPageReqDto;
import com.usian.model.media.dtos.WmNewsResultDTO;
import com.usian.model.media.dtos.WmUserDto;
import com.usian.wemedia.entity.WmMaterial;
import com.usian.wemedia.entity.WmNews;
import com.usian.wemedia.entity.WmNewsMaterial;
import com.usian.wemedia.mapper.WmNewsMapper;
import com.usian.wemedia.service.IWmMaterialService;
import com.usian.wemedia.service.IWmNewsMaterialService;
import com.usian.wemedia.service.IWmNewsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.core.type.TypeReference;

import java.util.*;
import java.util.stream.Collectors;

import static com.usian.common.constants.message.WmNewsUpDownConstants.WM_NEWS_UP_OR_DOWN_TOPIC;

/**
 * <p>
 * 自媒体图文内容信息表 服务实现类
 * </p>
 *
 * @author usian
 * @since 2022-07-08
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements IWmNewsService {

    @Override
    public PageResult<WmNewsDto> findByPage(WmNewsPageReqDto wmNewsPageReqDto) {
        //对wmNewsPageReqDto进行判断
        if (wmNewsPageReqDto==null){
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID,"参数不正确");
        }
        //获取用户信息
        Integer userId = UserThreadLocalUtils.getUserId();
        if (userId==null){
            throw new LeadException(AppHttpCodeEnum.NEED_LOGIN,"未登录请去登录");
        }
        //设置分页查询
        Page<WmNews> page = new Page<>(wmNewsPageReqDto.getPage(),wmNewsPageReqDto.getSize());
        //设置查询条件
        //1.关键字查询
        LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        String keyword = wmNewsPageReqDto.getKeyword();
        lambdaQueryWrapper.eq(WmNews::getWmUserId,userId);
        //如果关键字不为空进行关键字查询
        if (!StringUtils.isEmpty(keyword)){
            lambdaQueryWrapper.like(WmNews::getTitle,keyword);
        }
        //所属频道id
        Integer channelId = wmNewsPageReqDto.getChannelId();
        //如果频道id不为空进行频道id等值查询
        if (channelId!=null){
            lambdaQueryWrapper.eq(WmNews::getChannelId,channelId);
        }
        //开始时间
        Date beginPubDate = wmNewsPageReqDto.getBeginPubDate();
        //结束时间
        Date endPubDate = wmNewsPageReqDto.getEndPubDate();
       //如果开始时间不为空 进行开始时间的大于等于查询
        if (beginPubDate!=null){
            lambdaQueryWrapper.ge(WmNews::getPublishTime,beginPubDate);
        }
        //如果结束时间不为空 进行结束时间的小于等于查询
        if (endPubDate!=null){
            lambdaQueryWrapper.le(WmNews::getPublishTime,endPubDate);
        }
        Integer status = wmNewsPageReqDto.getStatus();
        //进行审核查询
        if (status!=null && status!=-1){
            if (status==1){
                lambdaQueryWrapper.in(WmNews::getStatus,new Integer[]{1,3});
            }else if (status==4){
                lambdaQueryWrapper.in(WmNews::getStatus,new Integer[]{4,8,9});
            }else {
                lambdaQueryWrapper.eq(WmNews::getStatus,status);
            }
        }
        //返回查询后的数据
        IPage<WmNews> iPage = this.page(page, lambdaQueryWrapper);
        //如果最后查出来的数据为空则返回 没有该条件的数据
        if (CollectionUtils.isEmpty(iPage.getRecords())){
            throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST,"查询的数据不存在");
        }
        //封装pageresult
        List<WmNewsDto> wmNewsDtos = BeanHelper.copyWithCollection(iPage.getRecords(), WmNewsDto.class);
        return new PageResult<>(wmNewsPageReqDto.getPage(),wmNewsPageReqDto.getSize(),iPage.getTotal(),wmNewsDtos);
    }

    /**
     * 新增修改保存文章操作
     * @param wmNewsDto
     */
    @Autowired
    private IWmNewsMaterialService wmNewsMaterialService;

    @Autowired
    private IWmMaterialService wmMaterialService;

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;

    @Override
    public void submit(WmNewsDto wmNewsDto) {
        //对wmNewsDto进行校验不能为空   必须有标题和文章才能进行提交
        if (wmNewsDto == null || wmNewsDto.getTitle() == null || wmNewsDto.getContent() == null) {
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID, "必须有文章和标题");
        }
        //获取用户的id
        Integer userId = UserThreadLocalUtils.getUserId();
        if (userId == null) {
            //userId不能为空
            throw new LeadException(AppHttpCodeEnum.NEED_LOGIN);
        }
        //进行数据的转换 将wmnewsdto转换为wmnews
        WmNews wmNews = BeanHelper.copyProperties(wmNewsDto, WmNews.class);
        //如果是wmnewsDto里面有id的话说明是修改的操作
        if (wmNewsDto.getId() == null) {
            //赋初始值 创建时间 和关联的userId
            wmNews.setCreatedTime(new Date());
            wmNews.setWmUserId(userId);
        }
        //对提交的类型做判断
        if (!wmNewsDto.getDraft()) {
            //前端传过来的draft是否为草稿的状态 如果是存储为草稿的话为true 取反 则不会进来
            //前端传过来的draft如果不是草稿的话为 true 取反 则会进来
            //submit是提交的时间
            wmNews.setSubmitedTime(new Date());
        }
        //对前端传过来的image进行处理
        if (!CollectionUtils.isEmpty(wmNewsDto.getImages())) {
            //进行字符串的分割 分割好的图片
            String images = wmNewsDto.getImages().stream().collect(Collectors.joining(","));
            //赋值到wmnews
            wmNews.setImages(images);
        }
        //保存文章或修改文章的操作
        this.saveOrUpdate(wmNews);
        //如果是修改文章需要把中间表删除
        if (wmNewsDto.getId()!=null){
            wmNewsMaterialService.deleteByNewsId(wmNewsDto.getId());
        }
        /*类型转换 前端传过来的content是一个json类型 利用工具类将json转换为map类型
        [{\"type\":\"text\",\"value\":\"111111111111111\"}]
        转换为
        type:text
        value:111111111111111*/
        List<Map<String, String>> contents = JsonUtils.nativeRead(wmNewsDto.getContent(), new TypeReference<List<Map<String, String>>>() {});
        //新定义方法获取所有的url的存入集合 contents
         List<String> imageUrlList = parseImageUrl(contents);
         //获取每个url的的id
        List<Integer> materialIds = null;
        if (imageUrlList!=null){
            materialIds = getMaterialIds(userId,imageUrlList);
            wmNewsMaterialService.saveInfoBatch(wmNews.getId(),materialIds,0);
        }
        if (wmNewsDto.getImages()!=null){
            List<Integer> integerList = getMaterialIds(userId, wmNewsDto.getImages());
            wmNewsMaterialService.saveInfoBatch(wmNews.getId(),integerList,1);
        }
        if (!wmNewsDto.getDraft()){
            kafkaTemplate.send(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC,wmNews.getId().toString());
        }
    }

    /**
     * 删除文章
     * @param id
     */
    @Override
    public void deleteNews(Integer id) {
        //id为空返回
        if (id==null){
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID,"参数无效");
        }
        //获取userID
        Integer userId = UserThreadLocalUtils.getUserId();
        if (userId==null){
            throw new LeadException(AppHttpCodeEnum.NEED_LOGIN,"请先去登录");
        }
        LambdaQueryWrapper<WmNews> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WmNews::getId,id).eq(WmNews::getWmUserId,userId);
        WmNews wmNews = getOne(queryWrapper);
        if (wmNews==null){
            throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST,"数据不存在");
        }
        //判断是否审核通过
        if (wmNews.getStatus()==9&&wmNews.getEnable()){
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID,"当前文章已经上架或者发布所有不能删除");
        }
        //删除文章关联的素材的信息
        wmNewsMaterialService.deleteByNewsId(id);
        //删除文章信息
        removeById(id);
    }

    /**
     * 上下架功能
     * @param wmNewsDto
     */
    @Override
    public void downOrUp(WmNewsDto wmNewsDto) {
        if (wmNewsDto==null ||wmNewsDto.getId()==null){
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID,"参数无效");
        }
        if (wmNewsDto.getEnable()==null){
            throw new LeadException(AppHttpCodeEnum.PARAM_INVALID,"上下级状态不能为空");
        }
        Integer userId = UserThreadLocalUtils.getUserId();
        if (userId==null){
            throw new LeadException(AppHttpCodeEnum.NEED_LOGIN,"需要登陆后在操作");
        }
        LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(WmNews::getId,wmNewsDto.getId()).eq(WmNews::getWmUserId,userId);
        WmNews wmNews = getOne(lambdaQueryWrapper);
        if (wmNews==null){
            throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        if (wmNews.getStatus()!=9){
            throw new LeadException(AppHttpCodeEnum.NO_OPERATOR_AUTH,"数据处于上架状态无法下架");
        }
        WmNews wmNews1 = new WmNews();
        wmNews1.setId(wmNewsDto.getId());
        wmNews1.setEnable(wmNewsDto.getEnable());
        boolean b = updateById(wmNews1);
        if (!b){
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"删除失败");
        }
        HashMap map = new HashMap();
        map.put("wmNewsId",wmNewsDto.getId());
        map.put("enable",wmNewsDto.getEnable()?1:0);
        kafkaTemplate.send(WM_NEWS_UP_OR_DOWN_TOPIC,JsonUtils.toString(map));
    }

    /**
     * 查询需要发布的文章id
     * @return
     */
    @Override
    public List<Integer> findWmNewsIds() {
        LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(WmNews::getStatus, WmNewsResultDTO.Status.SUCCESS.getCode());
        List<WmNews> wmNewsList = list(lambdaQueryWrapper);
        if (CollectionUtils.isEmpty(wmNewsList)){
            throw new LeadException(AppHttpCodeEnum.DATA_NOT_EXIST,"没有待发布的数据");
        }
        List<Integer> idList = wmNewsList.stream().map(WmNews::getId).collect(Collectors.toList());
        return idList;
    }

    /**
     * 文章分页模糊查询
     * @return
     */
    @Override
    public PageResult<WmNewsResultDTO> findWmNewsPage(NewsAuthDto newsAuthDto) {
        Page page = new Page(newsAuthDto.getPage(),newsAuthDto.getSize());
        IPage<WmNewsResultDTO> iPage= getBaseMapper().selectWmNewsByPage(page,newsAuthDto);
        if (CollectionUtils.isEmpty(iPage.getRecords())){
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"查询数据为空");
        }
        return new PageResult<>(newsAuthDto.getPage(),newsAuthDto.getSize(),iPage.getTotal(),iPage.getRecords());
    }

    private List<Integer> getMaterialIds(Integer userId, List<String> imageUrlList) {
        LambdaQueryWrapper<WmMaterial> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(WmMaterial::getUserId,userId).in(WmMaterial::getUrl,imageUrlList);
        //返回的是本人的图片路径
        List<WmMaterial> urlList = wmMaterialService.list(lambdaQueryWrapper);
        if (urlList==null || imageUrlList.size()!= urlList.size()){
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"引用图片异常");
        }

        //通过urlList获取id
        List<Integer> collect = urlList.stream().map(WmMaterial::getId).collect(Collectors.toList());
        return collect;
    }

    /**
     * 获取所有的url
     * @param contents
     * @return
     */
    private List<String> parseImageUrl(List<Map<String, String>> contents) {
        //利用set集合去重
        Set<String> set = new HashSet<>();
        for (Map<String, String> content : contents) {
            //如果键是image的话获取值
            if (content.get("type").equals("image")){
                String url = content.get("value");
                set.add(url);
            }
        }
        ArrayList<String> list = new ArrayList();
        list.addAll(set);
        return list;
    }
}
